using System;
using System.Collections.Generic;
using UnityEngine;

namespace Scripts.Parameters
{
	public delegate void ParameterChangedCallBack<Collection,Entry>(Collection parameterCollection, Entry parameterEntry);

	public class ParameterChangedSignal<Collection,Entry> 
		where Entry : class
		where Collection : class
	{
		//信号没有检查两次订阅，在这种情况下需要两次订阅。
		struct SignalStruct
		{
			public ParameterChangedCallBack<Collection,Entry> mCallback;
			public Entry mEntry;
		};

		struct DelayedStruct
		{
			public Collection mCollection;
			public Entry mEntry;
		};

		List<SignalStruct> _listeners = new ();
		bool _isDispatching;//会存在调用中调用
		bool _isDestroyed;
		private List<SignalStruct> _scheduledRemovedListeners = new();
		private List<DelayedStruct> _scheduledDispatches = new();

		public ParameterChangedSignal()
		{
			_isDestroyed = false;
			_isDispatching = false;
		}

		~ParameterChangedSignal()
		{
			RemoveAllListeners();
			_isDestroyed = true;
		}

		/// <summary>
		/// 派发对应集合对应入口的变化
		/// </summary>
		/// <param name="parameterCollection">变化的集合</param>
		/// <param name="parameterEntry">对应入口</param>
		public void Dispatch(Collection parameterCollection, Entry parameterEntry)
		{
			if (_isDispatching)
			{
				foreach (var iter in _scheduledDispatches)
				{
					if (iter.mCollection == parameterCollection && iter.mEntry == parameterEntry)
					{
						return;
					}
				}
				_scheduledDispatches.Add(new DelayedStruct{mCollection = parameterCollection, mEntry = parameterEntry});
				return;
			}
			if (_listeners.Count < 1)
			{
				return;
			}
			_isDispatching = true;
			foreach (var listenerStruct in _listeners)
			{
				if (listenerStruct.mEntry != null && parameterEntry == listenerStruct.mEntry)
					listenerStruct.mCallback(parameterCollection, parameterEntry);
				if (_isDestroyed)
					return;
			}

			_isDispatching = false;
			if (_scheduledRemovedListeners.Count > 0)
			{
				foreach (var listenerStruct in _scheduledRemovedListeners)
				{
					if(listenerStruct.mEntry == null)
					{
						RemoveListener(listenerStruct.mCallback);
						break;
					}
					else
						RemoveListener(listenerStruct.mEntry,listenerStruct.mCallback);
				}
				_scheduledRemovedListeners =new();
			}
			if (_scheduledDispatches.Count > 0)
			{
				List<DelayedStruct> dispatches = _scheduledDispatches;
				_scheduledDispatches = new();
				foreach (var toDispatch in dispatches)
				{
					Dispatch(toDispatch.mCollection, toDispatch.mEntry);
				}
			}
		}

/// <summary>
/// 添加对应入口的订阅
/// </summary>
/// <param name="parameterEntry">对应的具体入口</param>
/// <param name="listenerMethod">回调</param>
		public void AddListener(Entry parameterEntry ,ParameterChangedCallBack<Collection,Entry> listenerMethod)
		{
			if (listenerMethod == null || parameterEntry == null)
				throw new ArgumentNullException( $"addListener listener Null not allow; parameterEntry:{parameterEntry },listenerMethod:{listenerMethod}");
			
			if (HasListener(parameterEntry,listenerMethod))
			{
				Debug.LogError( "addListener listener already exists");
				return;
			}
			if (_isDispatching)
			{
				_listeners = new List<SignalStruct>(_listeners);
			}
			_listeners.Add(new SignalStruct { mCallback = listenerMethod,mEntry = parameterEntry});
		}
		/// <summary>
		/// 取消该方法对应入口的订阅
		/// </summary>
		/// <param name="parameterEntry"></param>
		/// <param name="listenerMethod"></param>
		public void RemoveListener(Entry parameterEntry,ParameterChangedCallBack<Collection,Entry> listenerMethod)
		{
			if (_isDestroyed || _listeners.Count < 1)
				return;
			if (listenerMethod == null || parameterEntry == null)
				throw new ArgumentNullException($"parameterEntry:{parameterEntry},listenerMethod:{listenerMethod}");

			if (_isDispatching)
			{
				_scheduledRemovedListeners.Add(new SignalStruct { mCallback=listenerMethod, mEntry = parameterEntry});
				return;
			}

			for(int i = _listeners.Count -1 ; i >= 0 ; i--)
			{
				var listener = _listeners[i];
				if (listener.mEntry == parameterEntry && listener.mCallback == listenerMethod)
				{
					_listeners.Remove(listener);
					break;
				}
			}
		}
		/// <summary>
		/// 取消所有该方法的订阅
		/// </summary>
		/// <param name="listenerMethod"></param>
		public void RemoveListener(ParameterChangedCallBack<Collection,Entry> listenerMethod)
		{
			if (_isDestroyed || _listeners.Count < 1)
				return;
			if (listenerMethod == null)
				throw new ArgumentNullException($"listenerMethod:{listenerMethod}");

			if (_isDispatching)
			{
				_scheduledRemovedListeners.Add(new SignalStruct { mCallback=listenerMethod, mEntry = null});
				return;
			}

			for(int i = _listeners.Count - 1 ; i >= 0 ; i--)
			{
				var listener = _listeners[i];
				if (listener.mCallback == listenerMethod)
				{
					_listeners.Remove(listener);
				}
			}
		}

		public void RemoveAllListeners()
		{
			if (_isDispatching)
				_listeners = new();
			else
				_listeners.Clear();
		}

		bool HasListener(Entry entry,ParameterChangedCallBack<Collection,Entry> method)
		{
			foreach (var listenersIterator in _listeners)
			{
				if (listenersIterator.mEntry == entry && listenersIterator.mCallback == method)
				{
					return true;
				}
			}
			return false;
		}
	}
}